SAM CLIを使ってLambda向けのコンテナイメージをビルド&デプロイしてみた #reinvent
CX事業本部@大阪の岩田です。
以下のブログでお伝えしたようにLambdaのパッケージフォーマットとしてコンテナイメージがサポートされるようになりました。
Lambdaの周辺ツールである、SAM CLIが既にコンテナイメージのパッケージに対応していたので、早速SAM CLIを使ってコンテナイメージ作成〜デプロイまで試してみました。
やってみる
SAM CLIのバージョンアップ
まずSAM CLIを最新化しておきましょう。
$pip install --upgrade aws-sam-cli $sam --version SAM CLI, version 1.13.1
現時点では1.13.1が最新版でした。
プロジェクトの作成
準備ができたのでsam init
してプロジェクトを初期化します。
$sam init
対話形式で色々と聞かれますが、パッケージ形式に関する選択肢が増えていることが分かります。What package type would you like to use?
の質問に対してImageを意味する2
を入力します。ベースとして使用するイメージはamazon/python3.8-base
を指定しました。このAWS公式イメージにはRICが内包されており、ランタイムAPIとのやりとりをRICにお任せすることができます。
Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 What package type would you like to use? 1 - Zip (artifact is a zip uploaded to S3) 2 - Image (artifact is an image uploaded to an ECR image repository) Package type: 2 Which base image would you like to use? 1 - amazon/nodejs12.x-base 2 - amazon/nodejs10.x-base 3 - amazon/python3.8-base 4 - amazon/python3.7-base 5 - amazon/python3.6-base 6 - amazon/python2.7-base 7 - amazon/ruby2.7-base 8 - amazon/ruby2.5-base 9 - amazon/go1.x-base 10 - amazon/java11-base 11 - amazon/java8.al2-base 12 - amazon/java8-base 13 - amazon/dotnetcore3.1-base 14 - amazon/dotnetcore2.1-base Base image: 3 Project name [sam-app]: sam-app-with-container-image Cloning app templates from https://github.com/aws/aws-sam-cli-app-templates ----------------------- Generating application: ----------------------- Name: sam-app-with-container-image Base Image: amazon/python3.8-base Dependency Manager: pip Output Directory: . Next steps can be found in the README file at ./sam-app-with-container-image/README.md
初期化できたらディレクトリを移動します。
$cd sam-app-with-container-image/
ディレクトリの中身を確認してみましょう。
$tree . ├── README.md ├── __init__.py ├── events │ └── event.json ├── hello_world │ ├── Dockerfile │ ├── __init__.py │ ├── app.py │ └── requirements.txt ├── samconfig.toml ├── template.yaml └── tests ├── __init__.py └── unit ├── __init__.py └── test_handler.py 4 directories, 12 files
hello_worldディレクトリ配下にDockerfileが作成されているところが分かります。
Dockerfileの中身は以下の通りでした
FROM public.ecr.aws/lambda/python:3.8 COPY app.py requirements.txt ./ RUN python3.8 -m pip install -r requirements.txt -t . # Command can be overwritten by providing a different command in the template directly. CMD ["app.lambda_handler"]
CMD
にLambdaのhandlerとなるファイルと関数が指定されています。
自動生成されたSAMテンプレートを確認してみましょう。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > python3.8 Sample SAM Template for sam-app-with-container-image # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: Timeout: 3 Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: PackageType: Image # ImageConfig: # Uncomment this to override command here from the Dockerfile # Command: ["app.lambda_handler"] Events: HelloWorld: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /hello Method: get Metadata: Dockerfile: Dockerfile DockerContext: ./hello_world DockerTag: python3.8-v1 Outputs: # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function # Find out more about other implicit resources you can reference within SAM # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api HelloWorldApi: Description: "API Gateway endpoint URL for Prod stage for Hello World function" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" HelloWorldFunction: Description: "Hello World Lambda Function ARN" Value: !GetAtt HelloWorldFunction.Arn HelloWorldFunctionIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt HelloWorldFunctionRole.Arn
HelloWorldFunctionに設定されているプロパティPackageType
とMetadata
に注目です。それぞれ以下の意味を持ちます。
- PackageType
- パッケージ形式を指定するプロパティで、
Zip
もしくはImage
が指定可能です
- パッケージ形式を指定するプロパティで、
- Metadata
sam build
実行時の振る舞いを制御するためのプロパティで、以下のプロパティが指定可能です- Dockerfile
- Dockerfileのファイル名を指定するプロパティです
- DockerContext
- Dockerfileの場所を指定するプロパティで、指定されたディレクトリがビルドコンテキストとなります
- DockerTag
- ビルドしたイメージに付与するタグを指定するプロパティ
- DockerBuildArgs
- ビルド時の
--build-arg
を指定するプロパティです
- ビルド時の
- Dockerfile
コンテナイメージのビルドとPUSH
続いてコンテナイメージをビルドします。今回は自動生成されたテンプレートから何も変更せずにビルドしてみます。
$sam build Building codeuri: . runtime: None metadata: {'Dockerfile': 'Dockerfile', 'DockerContext': './hello_world', 'DockerTag': 'python3.8-v1'} functions: ['HelloWorldFunction'] Building image for HelloWorldFunction function Setting DockerBuildArgs: {} for HelloWorldFunction function Step 1/4 : FROM public.ecr.aws/lambda/python:3.8 ---> c5a0f0b52673 Step 2/4 : COPY app.py requirements.txt ./ ---> eeb7dd5543ff Step 3/4 : RUN python3.8 -m pip install -r requirements.txt -t . ---> Running in 494d064dbb2a Collecting requests Downloading requests-2.25.0-py2.py3-none-any.whl (61 kB) Collecting certifi>=2017.4.17 Downloading certifi-2020.11.8-py2.py3-none-any.whl (155 kB) Collecting urllib3<1.27,>=1.21.1 Downloading urllib3-1.26.2-py2.py3-none-any.whl (136 kB) Collecting idna<3,>=2.5 Downloading idna-2.10-py2.py3-none-any.whl (58 kB) Collecting chardet<4,>=3.0.2 Downloading chardet-3.0.4-py2.py3-none-any.whl (133 kB) Installing collected packages: certifi, urllib3, idna, chardet, requests Successfully installed certifi-2020.11.8 chardet-3.0.4 idna-2.10 requests-2.25.0 urllib3-1.26.2 WARNING: You are using pip version 20.2.1; however, version 20.3 is available. You should consider upgrading via the '/var/lang/bin/python3.8 -m pip install --upgrade pip' command. ---> d05bfcc30f1e Step 4/4 : CMD ["app.lambda_handler"] ---> Running in 7370c01ca4aa ---> 942107bcba50 Successfully built 942107bcba50 Successfully tagged helloworldfunction:python3.8-v1 Build Succeeded Built Artifacts : .aws-sam/build Built Template : .aws-sam/build/template.yaml Commands you can use next ========================= [*] Invoke Function: sam local invoke [*] Deploy: sam deploy --guided
sam build
を実行するとdocker build
まで実行され、コンテナイメージがビルドされていることが分かります。
続いてビルドしたコンテナイメージをECRにPUSHします。このあたりの作業はsam build
やsam deploy
で自動作成されないので、自分で対応する必要があります。
$aws ecr create-repository --repository-name helloworldfunction --image-tag-mutability MUTABLE --image-scanning-configuration scanOnPush=true { "repository": { "repositoryArn": "arn:aws:ecr:ap-northeast-1:<AWSアカウントID>:repository/helloworldfunction", "registryId": "<AWSアカウントID>", "repositoryName": "helloworldfunction", "repositoryUri": "<AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/helloworldfunction", "createdAt": 1606889269.0, "imageTagMutability": "MUTABLE", "imageScanningConfiguration": { "scanOnPush": true }, "encryptionConfiguration": { "encryptionType": "AES256" } } }
リポジトリが作成できたらログインします。
$aws ecr get-login-password | docker login --username AWS --password-stdin <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com Login Succeeded
ローカルのイメージにタグを付与してECRにPUSHします
$docker tag helloworldfunction:python3.8-v1 <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/helloworldfunction:python3.8-v1 $docker push <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/helloworldfunction:python3.8-v1 The push refers to repository [<AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/helloworldfunction] b2fd08fab701: Pushed b3766120b913: Pushed 9b79aa2a550c: Pushed 8089fc755039: Pushed 120614c3628c: Pushed 2c1b97dd87b9: Pushed 57f5bfde13ee: Pushed af6d16f2417e: Pushed python3.8-v1: digest: sha256:7c3abe75461f5564951442ceaa267b8c6b282ae41da3f0276f21cdd12e4fe1b4 size: 1999
これで準備完了です
SAM CLIでデプロイする
準備ができたのでデプロイします。対話形式でコンテナイメージのリポジトリを聞かれるので、先程作成したECRのリポジトリのURIを入力します。
$ sam deploy --guided Configuring SAM deploy ====================== Looking for config file [samconfig.toml] : Not found Setting default arguments for 'sam deploy' ========================================= Stack Name [sam-app]: lambda-pkgfmt-container-test AWS Region [us-east-1]: ap-northeast-1 Image Repository []: <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/helloworldfunction Images that will be pushed: helloworldfunction:python3.8-v1 to <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/helloworldfunction:helloworldfunction-942107bcba50-python3.8-v1 #Shows you resources changes to be deployed and require a 'Y' to initiate deploy Confirm changes before deploy [y/N]: y #SAM needs permission to be able to create roles to connect to the resources in your template Allow SAM CLI IAM role creation [Y/n]: y HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y Save arguments to configuration file [Y/n]: y SAM configuration file [samconfig.toml]: SAM configuration environment [default]: Looking for resources needed for deployment: Not found. Creating the required resources... Successfully created! Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-69i44xrx71t3 A different default S3 bucket can be set in samconfig.toml Saved arguments to config file Running 'sam deploy' for future deployments will use the parameters saved above. The above parameters can be changed by modifying samconfig.toml Learn more about samconfig.toml syntax at https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html The push refers to repository [<AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/helloworldfunction] b2fd08fab701: Layer already exists b3766120b913: Layer already exists 9b79aa2a550c: Layer already exists 8089fc755039: Layer already exists 120614c3628c: Layer already exists 2c1b97dd87b9: Layer already exists 57f5bfde13ee: Layer already exists af6d16f2417e: Layer already exists helloworldfunction-942107bcba50-python3.8-v1: digest: sha256:7c3abe75461f5564951442ceaa267b8c6b282ae41da3f0276f21cdd12e4fe1b4 size: 1999 Deploying with following values =============================== Stack name : lambda-pkgfmt-container-test Region : ap-northeast-1 Confirm changeset : True Deployment image repository : <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/helloworldfunction Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-69i44xrx71t3 Capabilities : ["CAPABILITY_IAM"] Parameter overrides : {} Signing Profiles : {} Initiating deployment ===================== HelloWorldFunction may not have authorization defined. Uploading to lambda-pkgfmt-container-test/614deef9037e9199c68bda82754d59e7.template 1195 / 1195.0 (100.00%) Waiting for changeset to be created.. CloudFormation stack changeset ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Operation LogicalResourceId ResourceType Replacement ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Add HelloWorldFunctionHelloWorldPermissionProd AWS::Lambda::Permission N/A + Add HelloWorldFunctionRole AWS::IAM::Role N/A + Add HelloWorldFunction AWS::Lambda::Function N/A + Add ServerlessRestApiDeployment47fc2d5f9d AWS::ApiGateway::Deployment N/A + Add ServerlessRestApiProdStage AWS::ApiGateway::Stage N/A + Add ServerlessRestApi AWS::ApiGateway::RestApi N/A ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:<AWSアカウントID>:changeSet/samcli-deploy1606891016/7f41b30b-38ac-4c48-b65f-b0c76dc19d39 Previewing CloudFormation changeset before deployment ====================================================== Deploy this changeset? [y/N]: y 2020-12-02 15:37:23 - Waiting for stack create/update to complete CloudFormation events from changeset ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ResourceStatus ResourceType LogicalResourceId ResourceStatusReason ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- CREATE_IN_PROGRESS AWS::IAM::Role HelloWorldFunctionRole - CREATE_IN_PROGRESS AWS::IAM::Role HelloWorldFunctionRole Resource creation Initiated CREATE_COMPLETE AWS::IAM::Role HelloWorldFunctionRole - CREATE_IN_PROGRESS AWS::Lambda::Function HelloWorldFunction - CREATE_IN_PROGRESS AWS::Lambda::Function HelloWorldFunction Resource creation Initiated CREATE_COMPLETE AWS::Lambda::Function HelloWorldFunction - CREATE_IN_PROGRESS AWS::ApiGateway::RestApi ServerlessRestApi Resource creation Initiated CREATE_IN_PROGRESS AWS::ApiGateway::RestApi ServerlessRestApi - CREATE_COMPLETE AWS::ApiGateway::RestApi ServerlessRestApi - CREATE_IN_PROGRESS AWS::Lambda::Permission HelloWorldFunctionHelloWorldPermissionProd Resource creation Initiated CREATE_IN_PROGRESS AWS::ApiGateway::Deployment ServerlessRestApiDeployment47fc2d5f9d - CREATE_IN_PROGRESS AWS::Lambda::Permission HelloWorldFunctionHelloWorldPermissionProd - CREATE_IN_PROGRESS AWS::ApiGateway::Deployment ServerlessRestApiDeployment47fc2d5f9d Resource creation Initiated CREATE_COMPLETE AWS::ApiGateway::Deployment ServerlessRestApiDeployment47fc2d5f9d - CREATE_IN_PROGRESS AWS::ApiGateway::Stage ServerlessRestApiProdStage - CREATE_IN_PROGRESS AWS::ApiGateway::Stage ServerlessRestApiProdStage Resource creation Initiated CREATE_COMPLETE AWS::ApiGateway::Stage ServerlessRestApiProdStage - CREATE_COMPLETE AWS::Lambda::Permission HelloWorldFunctionHelloWorldPermissionProd - CREATE_COMPLETE AWS::CloudFormation::Stack lambda-pkgfmt-container-test - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- CloudFormation outputs from deployed stack -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Outputs -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Key HelloWorldFunctionIamRole Description Implicit IAM Role created for Hello World function Value arn:aws:iam::<AWSアカウントID>:role/lambda-pkgfmt-container-tes-HelloWorldFunctionRole-1PXZX592JZIIW Key HelloWorldApi Description API Gateway endpoint URL for Prod stage for Hello World function Value https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/ Key HelloWorldFunction Description Hello World Lambda Function ARN Value arn:aws:lambda:ap-northeast-1:<AWSアカウントID>:function:lambda-pkgfmt-container-test-HelloWorldFunction-3JMCGF5J66UP -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Successfully created/updated stack - lambda-pkgfmt-container-test in ap-northeast-1
しばらく待つとデプロイ完了です。
デプロイされたLambdaを確認してみましょう。
パッケージ形式:イメージ でデプロイされていることが分かります。
最後に以下のcurlコマンドを実行しAPI GW経由でLambdaを実行してみます。
$curl https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/ {"message": "hello world"}
無事にレスポンスが返ってきました。
まとめ
SAM CLIを使ったコンテナイメージの作成とデプロイを試してみました。ツールが対応しているので、とても簡単ですね。コンテナイメージをLambdaにデプロイするためのCI/CDパイプラインの整備なんかもやりやすそうです。SAMユーザーの方はLambdaのパッケージ形式として従来のZIPだけではなく、コンテナイメージという選択肢も検討してみてはいかがでしょうか?